<template>
  <div class="dogeo-map">
    <div class="map-container">
      <div :id="id" style="width:100%;height:100%"></div>
    </div>
    <div v-if="setting.enableCoordinate && (info.lng||info.lat||info.height)" class="cesium-info">
      <span v-if="setting.enableClickCoord">
        <span v-if="info.clickLng || info.clickLat">点击经纬度:{{ info.clickLng }},{{ info.clickLat }}</span>&nbsp;
      </span>
      <span v-if="info.lng">经度:{{ info.lng }}</span>&nbsp;
      <span v-if="info.lat">纬度:{{ info.lat }}</span>&nbsp;
      <span v-if="info.zoom">层级:{{ info.zoom }}</span>&nbsp;
      <span v-if="info.height">视角高:{{ info.height }}km</span>&nbsp;
      <span v-if="info.heading">方向:{{ info.heading }}°</span>&nbsp;
      <span v-if="info.pitch">俯仰角:{{ info.pitch }}°</span>&nbsp;
      <span v-if="info.roll">翻滚角:{{ info.roll }}°</span>&nbsp;
    </div>
    <slot name="menu">
      <div class="map-menu">
        <slot name="menu-start"></slot>
        <el-popover
          placement="right-start"
          title=""
          width="200"
          trigger="hover"
          content="地图设置"
          popper-class="popover-plain">
          <span @click="toggleSetting" slot="reference" class="menu-icon"><i class="el-icon-setting"></i></span>
        </el-popover>
        <slot name="menu-end"></slot>
        <!-- <el-popover
          placement="right-start"
          title=""
          width="320"
          trigger="hover"
          content="帮助"
          popper-class="popover-plain">
          <span slot="reference" class="menu-icon"><i class="el-icon-question"></i></span>

        </el-popover> -->
      </div>
    </slot>
    <el-drawer
      title="地图设置"
      :visible.sync="isShowSetting"
      :direction="direction"
      :append-to-body="true"
      @opened="handleOpenDrawer"
      size="320px"
      custom-class="drawer-active">
      <div class="box-info">
        <el-form ref="form" :model="form" label-width="80px" size="small">
          <el-form-item label="地图图层">
            <div style="overflow:hidden;padding: 6px 0;border: 1px solid #DCDFE6;border-radius: 4px;">
              <el-tree
                :data="mapLayers"
                show-checkbox
                node-key="id"
                @check-change="handleChangeLayers"
                :props="{ children: 'layers', label: 'name' }"
                ref="layers">
              </el-tree>
            </div>
          </el-form-item>
          <el-form-item label="经度">
            <el-input v-model="destination.lng" @change="handleDestOrient"></el-input>
          </el-form-item>
          <el-form-item label="纬度">
            <el-input v-model="destination.lat" @change="handleDestOrient"></el-input>
          </el-form-item>
          <el-form-item label="高度">
            <el-input v-model="destination.height" @change="handleDestOrient"></el-input>
          </el-form-item>
          <el-form-item label="偏航角">
            <el-input v-model="orientation.heading" @change="handleDestOrient"></el-input>
          </el-form-item>
          <el-form-item label="俯仰角">
            <el-input v-model="orientation.pitch" @change="handleDestOrient"></el-input>
          </el-form-item>
          <el-form-item label="翻转角">
            <el-input v-model="orientation.roll" @change="handleDestOrient"></el-input>
          </el-form-item>
          <el-form-item label="坐标信息">
            <el-switch v-model="setting.enableCoordinate" @change="handleStore"></el-switch>
          </el-form-item>
          <el-form-item label="点击信息">
            <el-switch v-model="setting.enableClickCoord" @change="handleStore"></el-switch>
          </el-form-item>
          <el-form-item label="罗盘">
            <el-switch v-model="setting.enableCompass" @change="handleStore"></el-switch>
          </el-form-item>
          <el-form-item label="缩放">
            <el-switch v-model="setting.enableZoomControls" @change="handleStore"></el-switch>
          </el-form-item>
          <el-form-item label="比例尺">
            <el-switch v-model="setting.enableDistanceLegend" @change="handleStore"></el-switch>
          </el-form-item>
          <el-form-item label="亮度">
            <el-slider
              style="width:80px"
              v-model="setting.brightness"
              @change="handleStore"
              :step="0.1"
              :min="0"
              :max="5"
            ></el-slider>
          </el-form-item>
          <div class="setting-btns">
            <el-button @click="handleResetSetting" size="small">重置</el-button>
          </div>
        </el-form>
      </div>
    </el-drawer>
    <slot></slot>
  </div>
</template>

<script>
import map, { Cesium } from '@/components/dogeo/cesium/map.js'
import cesiumConfig from '@/components/dogeo/cesium/config.js'
import view from '@/components/dogeo/cesium/viewer.js'
import camera from '@/components/dogeo/cesium/camera.js'
import layer from '@/components/dogeo/cesium/layer.js'
import navigation from '@/components/dogeo/cesium/widget/navigation/navigation.js'
import providers from '@/components/dogeo/providers/providers.js'
import ebus from '@/components/ebus.js'

export default {
  name: 'dogeo-map',

  props: {
    options: {
      type: Object,
      default () {
        return Object.assign({
          isStoreLayers: true
        }, JSON.parse(JSON.stringify(cesiumConfig)))
      }
    }
  },

  computed: {
    destination () {
      return this.config.destination
    },
    orientation () {
      return this.config.orientation
    },
    setting () {
      return this.config.setting
    }
  },

  data() {
    return {
      viewer: null,
      layer: layer,
      config: JSON.parse(JSON.stringify(cesiumConfig)),
      id: 'cesium_container_' + parseInt(Date.now() * Math.random()),
      form: {
        mode: 'web_mercator',
        layers: [1002, 1004]
      },
      // 地图图层类集合
      mapLayers: providers,
      direction: 'ltr',
      // 地图设置
      isShowSetting: false,
      // 配置存储键
      storeKey: 'dogeo-map-config',
      // 地理信息
      info: {
        lng: '',
        lat: '',
        height: '',
        heading: '',
        pitch: '',
        roll: '',
        zoom: '',
        clickLng: '',
        clickLat: '',
        clickHeight: ''
      }
    }
  },

  watch: {
    options: {
      deep: true,
      handler() {
        this.mergeOptions()
      }
    }
  },

  created () {
    // 合并配置
    this.mergeOptions()
  },

  mounted() {
    this.initMap()
  },

	methods: {
    // 合并配置
    mergeOptions () {
      // 默认坐标
      let destination = this.config.destination
      // 默认航角
      let orientation = this.config.orientation
      // 相机设置
      let camera = this.config.camera
      // 默认设置
      let setting = this.config.setting
      // 取本地存储的设置
      let options = this.options
      if (options.destination) {
        Object.assign(destination, options.destination)
      }
      if (options.orientation) {
        Object.assign(orientation, options.orientation)
      }
      if (options.camera) {
        Object.assign(camera, options.camera)
      }
      if (options.setting) {
        Object.assign(setting, options.setting)
      }
      if (options.layers) {
        this.config.layers = options.layers
      }
    },
    // 初始化地图
		initMap() {
      // 默认坐标
      let destination = this.config.destination
      // 默认航角
      let orientation = this.config.orientation
      // 默认设置
      let setting = this.config.setting
      // 取本地存储的设置
      let config = localStorage.getItem(this.storeKey)
      if (/{/.test(config)) {
        config = JSON.parse(config)
        // 转数字
        for (let key in config.destination) {
          config.destination[key] = parseFloat(config.destination[key]) || 0
        }
        for (let key in config.orientation) {
          config.orientation[key] = parseFloat(config.orientation[key]) || 0
        }
        if (this.options.isStoreLayers && Array.isArray(config.layers) && config.layers.length) {
          this.config.layers = config.layers
        }
        // 合并配置
        Object.assign(destination, config.destination)
        Object.assign(orientation, config.orientation)
        Object.assign(setting, config.setting)
      }
      // 图层
      this.form.layers = this.config.layers
      // 视图初始化
      let viewer = map.init({
        id: this.id,
        CESIUM_BASE_URL: this.options.CESIUM_BASE_URL || this.config.CESIUM_BASE_URL,
        orientation,
        destination
      })
      this.viewer = viewer
      // 设置默认底图
      this.renderBaseLayers()
      // 地理信息显示
      view.syncViewInfo(viewer, (data) => {
        this.info = Object.assign(this.info, data)
      })
      // 罗盘设置
      navigation.setCompass(viewer, { destination })
      // 点击事件传递
      const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
      handler.setInputAction(function (e) {
        ebus.$emit('onClick', e, viewer)
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
      // 加载完成
      this.$emit('mounted', this)
		},
    // 渲染图层
    renderBaseLayers () {
      let layers = this.getBaseLayers()
      layers = layers.map(item => {
        return {
          ...item.map.params,
          ...item.layer,
          isShow: true
        }
      })
      // 图层渲染
      layer.renderImageLayers(layers)
    },
    // 获取选择的图层
    getBaseLayers () {
      let layers = this.form.layers
      let nodes = []
      this.mapLayers.forEach(item => {
        item.layers.forEach(node => {
          if (layers.includes(node.id)) {
            nodes.push({ map: item, layer: node })
          }
        })
      })
      return nodes
    },
    // 地图图层更改
    handleChangeLayers () {
      let nodes = this.$refs.layers.getCheckedNodes()
      this.form.layers = nodes.filter(item => item.url).map(item => item.id)
      this.renderBaseLayers()
      // 是否缓存图层配置
      if (this.options.isStoreLayers) {
        this.config.layers = this.form.layers
        clearTimeout(this.storeTimer)
        this.storeTimer = setTimeout(() => {
          localStorage.setItem(this.storeKey, JSON.stringify(this.config))
        }, 500)
      }
    },
    // 打开窗口
    handleOpenDrawer () {
      if (!this.isOpened) {
        this.isOpened = true
        // 设置默认底图
        this.$refs.layers.setCheckedKeys(this.form.layers, true)
      }
      let ori = camera.getOrientation(this.viewer)
      Object.assign(this.config.destination, ori)
    },
    // 关闭窗口
    handleCloseDrawer(done) {
      done()
    },
    // 亮度设置
    brightChange () {
      let viewer = this.viewer
      let brightness = Number(this.config.setting.brightness)
      if (!this.brightnessInit) {
        this.brightnessInit = true
        var stages = viewer.scene.postProcessStages
        viewer.scene.brightness = viewer.scene.brightness || stages.add(Cesium.PostProcessStageLibrary.createBrightnessStage())
        viewer.scene.brightness.enabled = true
        viewer.scene.brightness.uniforms.brightness = Number(brightness)
      }
      if (brightness > 5) {
        brightness = 5
      } else if (brightness < 0) {
        brightness = 0
      }
      this.viewer.scene.brightness.uniforms.brightness = brightness
    },
    // 设置相机姿态
    setOrientation () {
      let orientation = this.config.orientation
      this.viewer.camera.setView({
        // 指定相机视角
        orientation: {
          heading: Cesium.Math.toRadians(parseFloat(orientation.heading)),
          pitch: Cesium.Math.toRadians(parseFloat(orientation.pitch)),
          roll: parseFloat(orientation.roll)
        }
      })
    },
    // 切换设置
    toggleSetting () {
      this.isShowSetting = !this.isShowSetting
    },
    // 重置设置
    handleResetSetting () {
      this.config = JSON.parse(JSON.stringify(cesiumConfig))
      localStorage.setItem(this.storeKey, '')
    },
    // 保存设置
    handleStore () {
      clearTimeout(this.storeTimer)
      this.storeTimer = setTimeout(() => {
        let value = this.config.setting
        let el = document.querySelector('.compass')
        el && (el.style.display = value.enableCompass ? 'block' : 'none')
        el = document.querySelector('.navigation-controls')
        el && (el.style.display = value.enableZoomControls ? 'block' : 'none')
        el = document.querySelector('#distanceLegendDiv')
        el && (el.style.display = value.enableDistanceLegend ? 'block' : 'none')
        // 亮度
        this.brightChange()
        this.setOrientation()
        localStorage.setItem(this.storeKey, JSON.stringify(this.config))
      }, 500)
    },
    handleDestOrient () {
      clearTimeout(this.destTimer)
      this.destTimer = setTimeout(() => {
        let destination = this.config.destination
        let orientation = this.config.orientation
        camera.flyToPoint(
          parseFloat(destination.lng), parseFloat(destination.lat), parseFloat(destination.height),
          undefined,
          parseFloat(orientation.heading), parseFloat(orientation.pitch), parseFloat(orientation.roll)
        )
        this.handleStore()
      }, 1000)
    }
	}
}
</script>

<style lang="less" scoped>
.box-info {
  padding: 4px 4px 56px;
  .el-form-item {
    margin-bottom: 8px;
  }
  .checkbox-min {
    .el-checkbox {
      margin-right: 8px;
      width: 42px;
      line-height: 18px;
    }
  }
  .el-checkbox__label {
    padding-left: 6px;
  }
  .el-select {
    display: block;
  }
  .btns-footer {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 8px;
    text-align: center;
    border-top: 1px solid #EBEEF5;
    z-index: 11;
    background: rgba(255, 255, 255, 0.8);
  }
}
.map-container {
  width: 100%;
  height: 100%;
}
#cesium_container {
  position: relative;
  width: 100%;
  height: 100%;
}
.cesium-info {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  font-size: 12px;
  color: #fff;
  line-height: 24px;
  text-align: right;
  z-index: 2;
  background: rgba(0, 0, 0, .3);
}
.setting-btns {
  text-align: center;
}
</style>

<style lang="less">
@import './cesium/widget/navigation/style/navigation.less';
.dogeo-map {
  position: relative;
  .map-menu {
    position: absolute;
    left: 0;
    top: 0;
    padding: 4px;
    z-index: 9;
    .menu-icon {
      display: block;
      box-sizing: border-box;
      margin-bottom: 4px;
      padding: 5px;
      width: 32px;
      height: 32px;
      line-height: 22px;
      font-weight: 700;
      border-radius: 2px;
      cursor: pointer;
      background: #303336;
      border: 1px solid #444;
      color: #edffff;
      text-align: center;
      &:hover {
        color: #fff;
        background: #48b;
        border-color: #aef;
        box-shadow: 0 0 8px #fff;
      }
    }
  }
}
.drawer-active {
  .el-drawer__header {
    margin-bottom: 0;
    padding: 8px 10px 8px;
    font-weight: 700;
  }
  [role=heading] {
    font-size: 14px;
  }
  .el-drawer__body::-webkit-scrollbar {
    width: 6px;
    height: 6px;
    background-color: #F5F5F5;
  }
  /*定义滚动条轨道 内阴影+圆角*/
  .el-drawer__body::-webkit-scrollbar-track {
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.1);
    border-radius: 10px;
    background-color: #F5F5F5;
  }
  /*定义滑块 内阴影+圆角*/
  .el-drawer__body::-webkit-scrollbar-thumb {
    border-radius: 10px;
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.1);
    background-color: #ccc;
  }
}
.el-popper.popover-plain {
  padding: 8px 10px;
}
.el-drawer__wrapper[for=tool-content] {
  width: 320px;
  left: auto;
  right: 0;
}
</style>